package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 定义命令行参数
	var (
		actionName  string
		runtimeKind string
		memorySize  string
		timeout     string
		priority    string
		threshold    string
		file string
		main string
	)

	// 设置参数默认值（与原硬编码值一致）
	flag.StringVar(&actionName, "action", "test", "Action名称")
	flag.StringVar(&runtimeKind, "kind", "go:1.23", "运行时类型")
	flag.StringVar(&memorySize, "memory", "512", "内存大小（单位MB）")
	flag.StringVar(&timeout, "timeout", "100000", "超时时间（单位毫秒）")
	flag.StringVar(&priority, "priority", "1", "优先级(1-5)")
	flag.StringVar(&threshold, "threshold", "0", "任务阈值")
	flag.StringVar(&file, "file", "main-bin.zip", "文件名")
	flag.StringVar(&main, "main", "main", "主函数名称")
	flag.Parse()

	uri := "mongodb://localhost:30017"
	clientOptions := options.Client().ApplyURI(uri)
	// 连接到 MongoDB
	client, err := mongo.Connect(context.TODO(), clientOptions)
	if err != nil {
		fmt.Printf("[ERROR] 连接 MongoDB 失败: %v\n", err)
		os.Exit(1)
	}
	// 检查连接
	err = client.Ping(context.TODO(), nil)
	if err != nil {
		fmt.Printf("[ERROR] 连接 MongoDB 失败: %v\n", err)
		os.Exit(1)
	}

	// 构造wsk命令
	cmd := exec.Command("wsk",
		"action", "update",
		actionName,
		file,
		"--main", main,
		"--kind", runtimeKind,
		"--memory", memorySize,
		"--timeout", timeout,
		"--insecure")

	// 捕获命令输出
	output, err := cmd.CombinedOutput()
	// 错误处理
	if err != nil {
		fmt.Printf("[ERROR] 命令执行失败: %v\n", err)
		fmt.Printf("详细输出: \n%s\n", output)
		os.Exit(1)
	}

	// 选择数据库和集合
	database := client.Database("openwhisk")
	collection := database.Collection("actions")
	// 更新或插入文档
	err = UpsertDocumentAction(collection, actionName, memorySize,  priority, threshold,timeout,runtimeKind)
	if err != nil {
		fmt.Printf("[ERROR] 更新或插入文档失败: %v\n", err)
		os.Exit(1)
	}
	// 输出成功信息
	fmt.Printf("[SUCCESS] 操作成功: \n%s\n", output)
}

func UpsertDocumentAction(collection *mongo.Collection, actionName string, memorySize string,  priority string, threshold string,timeout string,runtimeKind string) error {
	// 将memorySize转换为int，cpuNum转换为float64，priority转换为int
	memorySizeInt, err := strconv.Atoi(memorySize)
	if err != nil {
		return fmt.Errorf("failed to convert memorySize to int: %v", err)
	}
	if err != nil {
		return fmt.Errorf("failed to convert cpuNum to float64: %v", err)
	}
	priorityInt, err := strconv.Atoi(priority)
	if priorityInt < 1 || priorityInt > 5 {
		return fmt.Errorf("优先级必须在 1-5 之间")
	}
	if err != nil {
		return fmt.Errorf("failed to convert priority to int: %v", err)
	}
	thresholdFloat, err := strconv.ParseFloat(threshold, 64)
	if err != nil {
		return fmt.Errorf("failed to convert threhold to float64: %v", err)
	}
	if thresholdFloat < 0 || thresholdFloat > 1 {
		return fmt.Errorf("任务阈值必须在 0-1 之间")
	}
	timeoutInt, err := strconv.ParseInt(timeout, 10, 64)
	if err != nil {
		return fmt.Errorf("failed to convert timeout to int: %v", err)
	}
	if timeoutInt < 0 {
		return fmt.Errorf("超时时间必须大于0")
	}
	// 构造更新的文档
	document := bson.M{
		"_id":        actionName,
		"memorySize": memorySizeInt,
		"priority":   priorityInt,
		"updateTime": time.Now(),
		"threshold":   thresholdFloat,
		"timeout":   timeoutInt,
		"runtime":   runtimeKind,
	}

	// 设置更新选项，开启Upsert
	upsert := true
	opts := options.Update().SetUpsert(upsert)

	// 更新或插入文档
	filter := bson.M{"_id": actionName}
	update := bson.M{"$set": document}
	_, err = collection.UpdateOne(context.TODO(), filter, update, opts)
	if err != nil {
		return fmt.Errorf("failed to upsert document: %v", err)
	}
	fmt.Println("Upserted document with actionName:", actionName)
	return nil
}
